/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import UIKit
import Shared
import SnapKit
import Foundation
import FxA
import Account

class AdvanceAccountSettingViewController: SettingsTableViewController {
    fileprivate let SectionHeaderIdentifier = "SectionHeaderIdentifier"
    
    fileprivate var customSyncUrl: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = Strings.SettingsAdvanceAccountSectionName
        self.customSyncUrl = self.profile.prefs.stringForKey(PrefsKeys.KeyCustomSyncWeb)
    }
    
    func clearCustomAccountPrefs() {
        self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService)
        self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncToken)
        self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncProfile)
        self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncOauth)
        self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncAuth)
        self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncWeb)
        
        // To help prevent the account being in a strange state, we force it to
        // log out when user clears their custom server preferences.
        self.profile.removeAccount()
    }
    
    func setCustomAccountPrefs(_ data: Data, url: URL) {        
        guard let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any] else {
            return
        }
        
        self.profile.prefs.setBool(true, forKey: PrefsKeys.KeyUseCustomSyncService)
        self.profile.prefs.setString(json["sync_tokenserver_base_url"] as! String, forKey: PrefsKeys.KeyCustomSyncToken)
        self.profile.prefs.setString(json["profile_server_base_url"] as! String, forKey: PrefsKeys.KeyCustomSyncProfile)
        self.profile.prefs.setString(json["oauth_server_base_url"] as! String, forKey: PrefsKeys.KeyCustomSyncOauth)
        self.profile.prefs.setString(json["auth_server_base_url"] as! String, forKey: PrefsKeys.KeyCustomSyncAuth)
        self.profile.prefs.setString(url.absoluteString, forKey: PrefsKeys.KeyCustomSyncWeb)
        self.profile.removeAccount()
        self.displaySuccessAlert()
    }
    
    func setCustomAccountPrefs() {
        guard let urlString = self.customSyncUrl, let url = URL(string: urlString) else {
            // If the user attempts to set a nil url, clear all the custom service perferences
            // and use default FxA servers.
            self.displayNoServiceSetAlert()
            return
        }
        
        // FxA stores its server configuation under a well-known path. This attempts to download the configuration
        // and save it into the users preferences.
        let syncConfigureString = urlString + "/.well-known/fxa-client-configuration"
        let syncConfigureURL = URL(string: syncConfigureString)!
        
        URLSession.shared.dataTask(with:syncConfigureURL, completionHandler: {(data, response, error) in
            guard let data = data, error == nil else {
                // Something went wrong while downloading or parsing the configuration.
                self.displayErrorAlert()
                return
            }
            self.setCustomAccountPrefs(data, url: url)
        }).resume()
    }
    
    func displaySuccessAlert() {
        let alertController = UIAlertController(title: "", message: Strings.SettingsAdvanceAccountUrlUpdatedAlertMessage, preferredStyle: .alert)
        let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlUpdatedAlertOk, style: .default, handler: nil)
        alertController.addAction(defaultAction)
        self.present(alertController, animated: true)
    }
    
    func displayErrorAlert() {
        self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService)
        DispatchQueue.main.async {
            self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
        }
        let alertController = UIAlertController(title: Strings.SettingsAdvanceAccountUrlErrorAlertTitle, message: Strings.SettingsAdvanceAccountUrlErrorAlertMessage, preferredStyle: .alert)
        let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlErrorAlertOk, style: .default, handler: nil)
        alertController.addAction(defaultAction)
        self.present(alertController, animated: true)
    }
    
    func displayNoServiceSetAlert() {
        self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService)
        DispatchQueue.main.async {
            self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
        }
        let alertController = UIAlertController(title: Strings.SettingsAdvanceAccountUrlErrorAlertTitle, message: NSLocalizedString("Please enter a custom account url before enabling.", comment: "No custom service set."), preferredStyle: .alert)
        let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlUpdatedAlertOk, style: .default, handler: nil)
        alertController.addAction(defaultAction)
        self.present(alertController, animated: true)
    }
    
    override func generateSettings() -> [SettingSection] {
        let prefs = profile.prefs
        let customSyncSetting = CustomSyncWebPageSetting(prefs: prefs,
                                                         prefKey: PrefsKeys.KeyCustomSyncWeb,
                                                         placeholder: Strings.SettingsAdvanceAccountUrlPlaceholder,
                                                         accessibilityIdentifier: "CustomSyncSetting",
                                                         settingDidChange: { fieldText in
                                                            self.customSyncUrl = fieldText
                                                            if let customSyncUrl = self.customSyncUrl, customSyncUrl.isEmpty {
                                                                self.clearCustomAccountPrefs()
                                                                return
                                                            }
        })
        
        var basicSettings: [Setting] = []
        basicSettings += [
            CustomSyncEnableSetting(
                prefs: prefs,
                settingDidChange: { result in
                    if result == true {
                        // Reload the table data to ensure that the updated custom url is set
                        self.tableView?.reloadData()
                        self.setCustomAccountPrefs()
                    } 
            }),
            customSyncSetting
        ]
        
        let settings: [SettingSection] = [
            SettingSection(title: NSAttributedString(string: ""), children: basicSettings),
            SettingSection(title: NSAttributedString(string: NSLocalizedString("To use a custom Firefox Account and sync servers, specify the root Url of the Firefox Account site. This will download the configuration and setup this device to use the new service. After the new service has been set, you will need to create a new Firefox Account or login with an existing one.", comment: "Details for using custom Firefox Account service.")), children: [])
        ]
        
        return settings
    }
    
    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderIdentifier) as! SettingsTableSectionHeaderFooterView
        let sectionSetting = settings[section]
        headerView.titleLabel.text = sectionSetting.title?.string
        
        switch section {
        // Hide the bottom border for the FxA custom server notes.
        case 1:
            headerView.titleAlignment = .top
            headerView.titleLabel.numberOfLines = 0
            headerView.showBottomBorder = false
        default:
            return super.tableView(tableView, viewForHeaderInSection: section)
        }
        return headerView
    }
}

class CustomSyncEnableSetting: BoolSetting {
    init(prefs: Prefs, settingDidChange: ((Bool?) -> Void)? = nil) {
        super.init(
            prefs: prefs, prefKey: PrefsKeys.KeyUseCustomSyncService, defaultValue: false,
            attributedTitleText: NSAttributedString(string: NSLocalizedString("Use Custom Account Service", tableName: "UseCustomAccountService", comment: "Toggle switch to use custom FxA server")),
            settingDidChange: settingDidChange
        )
    }
}

class CustomSyncWebPageSetting: WebPageSetting {
    override init(prefs: Prefs, prefKey: String, defaultValue: String? = nil, placeholder: String, accessibilityIdentifier: String, settingDidChange: ((String?) -> Void)? = nil) {
        super.init(prefs: prefs,
                   prefKey: prefKey,
                   defaultValue: defaultValue,
                   placeholder: placeholder,
                   accessibilityIdentifier: accessibilityIdentifier,
                   settingDidChange: settingDidChange)
        textField.clearButtonMode = UITextFieldViewMode.always
    }
}
